using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Runtime.Common.Interface;
using Runtime.Common.Object;
using Runtime.Core.GameBehaviour;
using Runtime.DesignPattern;
using UnityEngine;

namespace Runtime.Module.GameGraphic
{
    public class EntityNode : MonoBehaviour, IEntityNode, IGameAwakeBehaviour, IGameDestroyBehaviour
    {
        [SerializeField] private GameObjectNodeInfoCtrl<Transform> _NodeInfoCtrl = new();

        [SerializeField] private GameObjectNodeInfoCtrl<Component> _ComponentInfoCtrl = new();

        private readonly Composite _composite = new();
        private Action _OnDestroy;

        public virtual Task Awake()
        {
            _NodeInfoCtrl.Init();
            _ComponentInfoCtrl.Init();
            return Task.CompletedTask;
        }

        public virtual Task Destroy()
        {
            destroyInvoke();
            return Task.CompletedTask;
        }

        public event Action OnDestroy
        {
            add => _OnDestroy += value;
            remove => _OnDestroy -= value;
        }

        public IGuidObject Id { get; } = new GuidObject();

        public void AddChild(IComposite number)
        {
            _composite.AddChild(number);
        }

        public void RemoveChild(IComposite number)
        {
            _composite.RemoveChild(number);
        }

        public List<T> GetNumbers<T>() where T : IComposite
        {
            return _composite.GetNumbers<T>();
        }

        public List<IComposite> GetNumbers()
        {
            return _composite.GetNumbers();
        }

        public void Foreach(Action<IComposite> match)
        {
            _composite.Foreach(match);
        }

        public void ForeachByRecursion(Action<IComposite> match)
        {
            _composite.ForeachByRecursion(match);
        }

        public T Find<T>(Func<IComposite, bool> fun) where T : IComposite
        {
            return _composite.Find<T>(fun);
        }

        public void Clear()
        {
            _composite.Clear();
        }

        public T GetComponent<T>(string path) where T : Component
        {
            return _ComponentInfoCtrl.GetComponent(path) as T;
        }

        public T GetComponentFromNode<T>(string path) where T : Component
        {
            var trans = _NodeInfoCtrl.GetComponent(path);
            return trans ? trans.GetComponent<T>() : null;
        }

        public Transform GetNode(string path)
        {
            return _NodeInfoCtrl.GetComponent(path);
        }

        public GameObject GetNodeOfGameObject(string path)
        {
            var trans = _NodeInfoCtrl.GetComponent(path);
            return trans ? trans.gameObject : null;
        }

        public List<T> GetComponents<T>() where T : Component
        {
            return _ComponentInfoCtrl.GetComponents<T>();
        }

        public List<Transform> GetNodes()
        {
            return _NodeInfoCtrl.GetNodes();
        }

        public List<GameObject> GetNodeOfGameObjects()
        {
            return _NodeInfoCtrl.GetNodeOfGameObjects();
        }


        private void destroyInvoke()
        {
            try
            {
                if (_OnDestroy == null) return;

                _OnDestroy.Invoke();
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
        }
    }
}